<template>
    <!-- #ifndef APP-NVUE -->
    <view
        :class="['uni-col', sizeClass, pointClassList]"
        :style="{
            paddingLeft: `${Number(gutter)}rpx`,
            paddingRight: `${Number(gutter)}rpx`
        }"
    >
        <slot></slot>
    </view>
    <!-- #endif -->
    <!-- #ifdef APP-NVUE -->
    <!-- 在nvue上，类名样式不生效，换为style -->
    <!-- 设置right正值失效，设置 left 负值 -->
    <view
        :class="['uni-col']"
        :style="{
            paddingLeft: `${Number(gutter)}rpx`,
            paddingRight: `${Number(gutter)}rpx`,
            width: `${nvueWidth}rpx`,
            position: 'relative',
            marginLeft: `${marginLeft}rpx`,
            left: `${right === 0 ? left : -right}rpx`
        }"
    >
        <slot></slot>
    </view>
    <!-- #endif -->
</template>

<script>
/**
 * Col	布局-列
 * @description	搭配uni-row使用，构建布局。
 * @tutorial	https://ext.dcloud.net.cn/plugin?id=3958
 *
 * @property	{span} type = Number 栅格占据的列数
 * 						默认 24
 * @property	{offset} type = Number 栅格左侧的间隔格数
 * @property	{push} type = Number 栅格向右移动格数
 * @property	{pull} type = Number 栅格向左移动格数
 * @property	{xs} type = [Number, Object] <768px 响应式栅格数或者栅格属性对象
 * 						@description	Number时表示在此屏幕宽度下，栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
 * @property	{sm} type = [Number, Object] ≥768px 响应式栅格数或者栅格属性对象
 * 						@description	Number时表示在此屏幕宽度下，栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
 * @property	{md} type = [Number, Object] ≥992px 响应式栅格数或者栅格属性对象
 * 						@description	Number时表示在此屏幕宽度下，栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
 * @property	{lg} type = [Number, Object] ≥1200px 响应式栅格数或者栅格属性对象
 * 						@description	Number时表示在此屏幕宽度下，栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
 * @property	{xl} type = [Number, Object] ≥1920px 响应式栅格数或者栅格属性对象
 * 						@description	Number时表示在此屏幕宽度下，栅格占据的列数。Object时可配置多个描述{span: 4, offset: 4}
 */
const ComponentClass = "uni-col";

// -1 默认值，因为在微信小程序端只给Number会有默认值0
export default {
    name: "UniCol",
    // #ifdef MP-WEIXIN
    options: {
        virtualHost: true // 在微信小程序中将组件节点渲染为虚拟节点，更加接近Vue组件的表现
    },
    // #endif
    props: {
        span: {
            type: Number,
            default: 24
        },
        offset: {
            type: Number,
            default: -1
        },
        pull: {
            type: Number,
            default: -1
        },
        push: {
            type: Number,
            default: -1
        },
        xs: [Number, Object],
        sm: [Number, Object],
        md: [Number, Object],
        lg: [Number, Object],
        xl: [Number, Object]
    },
    data() {
        return {
            gutter: 0,
            sizeClass: "",
            parentWidth: 0,
            nvueWidth: 0,
            marginLeft: 0,
            right: 0,
            left: 0
        };
    },
    computed: {
        sizeList() {
            let { span, offset, pull, push } = this;

            return {
                span,
                offset,
                pull,
                push
            };
        },
        // #ifndef APP-NVUE
        pointClassList() {
            let classList = [];

            ["xs", "sm", "md", "lg", "xl"].forEach((point) => {
                const props = this[point];
                if (typeof props === "number") {
                    classList.push(`${ComponentClass}-${point}-${props}`);
                } else if (typeof props === "object" && props) {
                    Object.keys(props).forEach((pointProp) => {
                        classList.push(
                            pointProp === "span"
                                ? `${ComponentClass}-${point}-${props[pointProp]}`
                                : `${ComponentClass}-${point}-${pointProp}-${props[pointProp]}`
                        );
                    });
                }
            });

            // 支付宝小程序使用 :class=[ ['a','b'] ]，渲染错误
            return classList.join(" ");
        }
        // #endif
    },
    watch: {
        sizeList: {
            immediate: true,
            handler(newVal) {
                // #ifndef APP-NVUE
                let classList = [];
                for (let size in newVal) {
                    const curSize = newVal[size];
                    if ((curSize || curSize === 0) && curSize !== -1) {
                        classList.push(
                            size === "span" ? `${ComponentClass}-${curSize}` : `${ComponentClass}-${size}-${curSize}`
                        );
                    }
                }
                // 支付宝小程序使用 :class=[ ['a','b'] ]，渲染错误
                this.sizeClass = classList.join(" ");
                // #endif
                // #ifdef APP-NVUE
                this.updateNvueWidth(this.parentWidth);
                // #endif
            }
        }
    },
    created() {
        // 字节小程序中，在computed中读取$parent为undefined
        let parent = this.$parent;

        while (parent && parent.$options.componentName !== "uniRow") {
            parent = parent.$parent;
        }

        this.updateGutter(parent.gutter);
        parent.$watch("gutter", (gutter) => {
            this.updateGutter(gutter);
        });

        // #ifdef APP-NVUE
        this.updateNvueWidth(parent.width);
        parent.$watch("width", (width) => {
            this.updateNvueWidth(width);
        });
        // #endif
    },
    methods: {
        updateGutter(parentGutter) {
            parentGutter = Number(parentGutter);
            if (!isNaN(parentGutter)) {
                this.gutter = parentGutter / 2;
            }
        },
        // #ifdef APP-NVUE
        updateNvueWidth(width) {
            // 用于在nvue端，span，offset，pull，push的计算
            this.parentWidth = width;
            ["span", "offset", "pull", "push"].forEach((size) => {
                const curSize = this[size];
                if ((curSize || curSize === 0) && curSize !== -1) {
                    let RPX = (1 / 24) * curSize * width;
                    RPX = Number(RPX);
                    switch (size) {
                        case "span":
                            this.nvueWidth = RPX;
                            break;
                        case "offset":
                            this.marginLeft = RPX;
                            break;
                        case "pull":
                            this.right = RPX;
                            break;
                        case "push":
                            this.left = RPX;
                            break;
                    }
                }
            });
        }
        // #endif
    }
};
</script>

<style lang="scss" scoped>
/* breakpoints */
$--sm: 768px !default;
$--md: 992px !default;
$--lg: 1200px !default;
$--xl: 1920px !default;

$breakpoints: (
    "xs": (
        max-width: $--sm - 1
    ),
    "sm": (
        min-width: $--sm
    ),
    "md": (
        min-width: $--md
    ),
    "lg": (
        min-width: $--lg
    ),
    "xl": (
        min-width: $--xl
    )
);

$layout-namespace: ".uni-";
$col: $layout-namespace + "col";

@function getSize($size) {
    /* TODO 1/24 * $size * 100 * 1%; 使用计算后的值，为了解决 vue3 控制台报错 */
    @return 0.04166666666 * $size * 100 * 1%;
}

@mixin res($key, $map: $breakpoints) {
    @if map-has-key($map, $key) {
        @media screen and #{inspect(map-get($map,$key))} {
            @content;
        }
    } @else {
        @warn "Undeinfed point: `#{$key}`";
    }
}

/* #ifndef APP-NVUE */
#{$col} {
    float: left;
    box-sizing: border-box;
}

#{$col}-0 {
    /* #ifdef APP-NVUE */
    width: 0;
    height: 0;
    margin-top: 0;
    margin-right: 0;
    margin-bottom: 0;
    margin-left: 0;
    /* #endif */
    /* #ifndef APP-NVUE */
    display: none;
    /* #endif */
}

@for $i from 0 through 24 {
    #{$col}-#{$i} {
        width: getSize($i);
    }

    #{$col}-offset-#{$i} {
        margin-left: getSize($i);
    }

    #{$col}-pull-#{$i} {
        position: relative;
        right: getSize($i);
    }

    #{$col}-push-#{$i} {
        position: relative;
        left: getSize($i);
    }
}

@each $point in map-keys($breakpoints) {
    @include res($point) {
        #{$col}-#{$point}-0 {
            display: none;
        }

        @for $i from 0 through 24 {
            #{$col}-#{$point}-#{$i} {
                width: getSize($i);
            }

            #{$col}-#{$point}-offset-#{$i} {
                margin-left: getSize($i);
            }

            #{$col}-#{$point}-pull-#{$i} {
                position: relative;
                right: getSize($i);
            }

            #{$col}-#{$point}-push-#{$i} {
                position: relative;
                left: getSize($i);
            }
        }
    }
}

/* #endif */
</style>
